home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1999 Spring / macformat-077.iso / Shareware Plus / Development / SpriteWorld 2.2 / SpriteWorld files / Utils / Brian's Extensions / SWTranslucentBlitters.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-01-14  |  42.7 KB  |  1,242 lines  |  [TEXT/CWIE]

  1. /*  -----------------------------------------------------------------------------------
  2.     -----------------------------------------------------------------------------------
  3.     SWTranslucentBlitters.c
  4.     
  5.     by Brian Roddy
  6.     
  7.     4/13/97
  8.  
  9.     Routines for blitting translucent sprites in 8 bit or in 16 bit mode.  Both versions
  10.     require a lookup table to work properly.  These lookup tables need to be initialized
  11.     before being used.  To initialize the 16 bit version, call 
  12.  
  13.     err = SWCreate16BitTranslucencyTable();
  14.  
  15.     This creates a table which supports 30 levels of translucency and is small.  The 8-bit 
  16.     table is much bigger.  It requires 256 * 256 bytes (or 64K) of memory for each level
  17.     of translucency.  It also takes a relatively long time to compute.  For this reason
  18.     we have a number of functions to allow creating these tables in advance and saving them
  19.     in the resource fork so they can be loaded quickly.  By default you can call:
  20.  
  21.     err = SWLoadOrCreate8BitTranslucencyTable(numLevelsOfTranslucency);
  22.  
  23.     This single purpose function will try and load the table from a resource.  If it
  24.     does not exist, it will create the table and save it to the resource fork before continuing.
  25.     This means that the first time you run the program, it will be slow and will compute
  26.     this and save it.  Next time you run the program it can just load it and thus will
  27.     start up quickly.  Note that you can go into ResEdit and copy a TTAB resource that
  28.     has been computed and paste it into your project's resource file.  This way, it will 
  29.     automatically be copied into your application's resource fork at link timeand therefore 
  30.     will never have to be computed.  (To reiterate, you run your program first. This 
  31.     generates the computed table and stores it in the TTAB resource.  You copy this resource 
  32.     into your project's resource file.  From then on this TTAB will get copied to your 
  33.     application so you won't have to wait for it to be computed each time you recompile 
  34.     and run.)
  35.     
  36.     More detailed functions for manipulating these tables exist.  See the source code
  37.     for more details in the comments.
  38.  
  39.  
  40.     Once you've called initialized the table or tables, you can set a Sprite's translucency
  41.     level with:
  42.  
  43.     SWSetSpriteTranslucencyLevel(mySpritePtr, 6)
  44.     
  45.     where mySpritePtr is a SpritePtr and 6 is a byte specifying the translucency level.
  46.     This level is a number from 1 to the number of Levels, where 1 is barely
  47.     visible and a higher number is more opaque.  If a level of any other value (e.g. 0
  48.     or >= number of levels)    is specified, the Sprite is considered fully opaque and is 
  49.     thus blitted normally.
  50.     
  51.     You can find a sprite's level of translucency with 
  52.     
  53.     SWGetSpriteTranslucencyLevel(mySpritePtr)
  54.  
  55.     which will return the level as a byte, or 0 if the sprite is opaque.
  56.     
  57.     IMPORTANT: The translucent blitters and idle Sprites do not mix! This means that each
  58.     translucent Sprite should have a MoveProc or FrameProc that is called every frame that
  59.     sets the Sprite's needsToBeDrawn flag to true.
  60.  
  61.  
  62.     -----------------------------------------------------------------------------------
  63.     Implementation Notes:
  64.  
  65.     The 8-bit blitter is fairly optimal.  There is some inline assembly to create four
  66.     pixel longs in a minimal number of operations.  Note that as the processor is much
  67.     faster than the bus, we spend a couple extra cycles to create this long so all
  68.     four can be passed at once.
  69.  
  70.     The 16-bit blitter is extremely optimized.  The bulk is written in assembly and uses
  71.     a lookup table.
  72.  
  73.     N.B.: Blitters are modified versions of blitters from SpriteWorld 2
  74.  
  75.     This source code is available for free use.
  76.     ----------------------------------------------------------------------------------- 
  77.     ----------------------------------------------------------------------------------- */
  78.  
  79.  
  80. #include "SWTranslucentBlitters.h"
  81.  
  82.  
  83. #pragma mark -----Public API-----
  84. ///--------------------------------------------------------------------------------------
  85. //    Setting and Getting translucency level
  86. ///--------------------------------------------------------------------------------------
  87.  
  88. SW_FUNC OSErr SWSetSpriteTranslucencyLevel(
  89.     SpritePtr srcSpriteP,
  90.     unsigned long level) 
  91. {
  92.     short         currentPixelDepth;
  93.     OSErr        err;
  94.     
  95.     
  96.     currentPixelDepth = (*srcSpriteP->frameArray[0]->framePort->portPixMap)->pixelSize;
  97.     err = kWrongDepthErr;
  98.     
  99.     srcSpriteP->translucencyLevel = level;
  100.     
  101.     if (currentPixelDepth == 8)
  102.     {
  103.         if ((level <= 0) || (level > gNumberOf8BitTranslucencyLevels)) {
  104.             srcSpriteP->frameDrawProc = BlitPixie8BitMaskDrawProc;
  105.         } else {
  106.             srcSpriteP->translucencyLevel--;
  107.             // preshift it 
  108.             srcSpriteP->translucencyLevel <<= 16;
  109.             srcSpriteP->frameDrawProc = BlitPixie8BitTranslucentMaskDrawProc;
  110.         }
  111.         err = noErr;
  112.     }
  113.     else if (currentPixelDepth == 16)
  114.     {
  115.         if ((level <= 0) || (level >= kNumberOf16BitTranslucencyLevels)) {
  116.             srcSpriteP->frameDrawProc = BlitPixieAllBitMaskDrawProc;
  117.         } else {
  118.             srcSpriteP->frameDrawProc = BlitPixie16BitTranslucentMaskDrawProc;
  119.         }
  120.         err = noErr;
  121.     }
  122.     SWSetStickyIfError( err );
  123.     return err;
  124. }
  125.  
  126.  
  127. SW_FUNC unsigned long SWGetSpriteTranslucencyLevel(SpritePtr srcSpriteP) {
  128.     short         currentPixelDepth;
  129.     currentPixelDepth = (*srcSpriteP->frameArray[0]->framePort->portPixMap)->pixelSize;
  130.     if (currentPixelDepth == 8)
  131.         if (srcSpriteP->frameDrawProc == BlitPixie8BitTranslucentMaskDrawProc)
  132.             return ((srcSpriteP->translucencyLevel) >> 16) + 1;
  133.         else 
  134.             return 0;
  135.     else if (currentPixelDepth == 16)
  136.         if (srcSpriteP->frameDrawProc == BlitPixie16BitTranslucentMaskDrawProc)
  137.             return srcSpriteP->translucencyLevel;
  138.         else 
  139.             return 0;
  140.     else
  141.         return 0;
  142. }
  143.  
  144.  
  145. ///--------------------------------------------------------------------------------------
  146. ///--------------------------------------------------------------------------------------
  147. ///--------------------------------------------------------------------------------------
  148. /// 8-Bit Routines
  149. ///--------------------------------------------------------------------------------------
  150. ///--------------------------------------------------------------------------------------
  151. ///--------------------------------------------------------------------------------------
  152.  
  153. #pragma mark -----8 Bit Table Management-----
  154.  
  155. //-----------------------------------------------------------------------------
  156. // 8-bit Translucency Table Management
  157. //-----------------------------------------------------------------------------
  158.  
  159. // The Lookup table which is indexed by a [translucencyLevel][sourceColor][translucentColor]
  160. // Note that all colors are 8-bit, so this thing is 64K * gNumberOf8BitTranslucencyLevels
  161. // For instance, 8 levels adds up to half a meg.
  162. unsigned char *g8BitTranslucencyTable = NULL;
  163.  
  164. // Our array for storing the current CLUT in an easily accessible fashion.
  165. RGBColor     kSystemColorArray[kNumberOfColors];
  166.  
  167. // Number of Levels we currently support
  168. int gNumberOf8BitTranslucencyLevels = 0;
  169.  
  170.  
  171. ///--------------------------------------------------------------------------------------
  172. // -- SWLoadOrCreate8BitTranslucencyTable --
  173. ///--------------------------------------------------------------------------------------
  174. // This function may be called to get the translucency table in memory.
  175. // It either loads a premade table from the resource fork of the app,
  176. // or if it does not exist.  calculates the table and saves it in the resource fork.
  177. // Note that each table is CLUT specific.  Therefore, set the CLUT
  178. // before calling this.
  179. // To save development time, after this calculates and saves the table into the
  180. // TTAB resource of your application, go into resedit and copy the TTAB resource 
  181. // from the application and paste it into your project's resource file.  This way
  182. // the resource will get added to your application at link time and you won't have  
  183. // to wait for it to recompute each time.
  184.  
  185. OSErr     SWLoadOrCreate8BitTranslucencyTable (int numberOfLevels) {
  186.     OSErr                tableAllocationErr = noErr;
  187.     OSErr                err = noErr;
  188.  
  189.     // Ignore if we've already done this.
  190.     if (g8BitTranslucencyTable == NULL) {
  191.     
  192.         // First try loading the table from the resource fork.
  193.         // Note we hard code it being in resource ID 128.  If you want
  194.         // to support multiple CLUTS, you can create multiple tables
  195.         // and store them under different resource IDs and load them
  196.         // when you load your CLUT.  You of course have to precompute 
  197.         // these tables
  198.         
  199.         err = SWLoad8BitTranslucencyTable(128);
  200.         
  201.         // If there is an error or the number of levels doesn't match up,
  202.         // then we have to compute it (which can take a little while)
  203.         if ((err != noErr) || (numberOfLevels != gNumberOf8BitTranslucencyLevels)) {
  204.             err = SWCreate8BitTranslucencyTable(numberOfLevels);
  205.             
  206.             // And save it when we're done
  207.             if (err == noErr) {
  208.                 err = SWSave8BitTranslucencyTable(128);
  209.             }
  210.         }
  211.     }
  212.     return err;
  213. }
  214.  
  215. ///--------------------------------------------------------------------------------------
  216. //  -- SWDispose8BitTranslucencyTable --
  217. ///--------------------------------------------------------------------------------------
  218. // This function must be called to clear the table from memory.
  219.  
  220. void     SWDispose8BitTranslucencyTable(void)
  221. {
  222.     // Only do this if we've created a table.
  223.     if (g8BitTranslucencyTable != NULL)
  224.     {
  225.         DisposePtr((Ptr)g8BitTranslucencyTable);
  226.         g8BitTranslucencyTable = NULL;
  227.         gNumberOf8BitTranslucencyLevels = 0;
  228.     }
  229. }
  230.  
  231. ///--------------------------------------------------------------------------------------
  232. //  -- SWCreate8BitTranslucencyTable --
  233. ///--------------------------------------------------------------------------------------
  234. // This function will allocate and compute a table with the specified number of levels.
  235.  
  236.  
  237. OSErr     SWCreate8BitTranslucencyTable (int numberOfLevels) {
  238.     OSErr                tableAllocationErr = noErr;
  239.     unsigned long        arraySize;
  240.  
  241.     // If we've already done this, get rid of the old one
  242.     if (g8BitTranslucencyTable != NULL) SWDispose8BitTranslucencyTable();
  243.     
  244.     // First we need to allocate the array.
  245.     arraySize = numberOfLevels * 65536 * sizeof(unsigned char);
  246.     g8BitTranslucencyTable = (unsigned char *)NewPtr(arraySize);
  247.     tableAllocationErr = MemError();
  248.  
  249.     // If we were able to then we continue loading or creating
  250.     // the table.
  251.     if (tableAllocationErr == noErr) {
  252.         // Store our number of levels
  253.         gNumberOf8BitTranslucencyLevels = numberOfLevels;
  254.         
  255.         // so we load up the CLUT into an array so we have fast access to it.
  256.         CreateCLUTTable();
  257.         // We compute the table (albeit slowly)
  258.         Calc8BitTranslucencyTable(numberOfLevels);
  259.     }
  260.  
  261.     return tableAllocationErr;
  262. }
  263.  
  264.  
  265. ///--------------------------------------------------------------------------------------
  266. //    SWLoad8BitTranslucencyTable
  267. ///--------------------------------------------------------------------------------------
  268. // This function will load the translucency table from a TTAB resource of the specified ID,
  269. // rather than recomputing it from scratch each time.  Note that the first byte in the 
  270. // resource specifies the number of levels of translucency.
  271.  
  272. OSErr SWLoad8BitTranslucencyTable(short resourceID) {
  273.     unsigned char        **TranslucencyTableHandle;
  274.     unsigned char        *TranslucencyTableData;
  275.     OSErr                err = noErr;
  276.     unsigned long         arraySize;
  277.     
  278.     // If we've already done this, get rid of the old one
  279.     if (g8BitTranslucencyTable != NULL) SWDispose8BitTranslucencyTable();
  280.  
  281.     // Try and get a handle on the stored table
  282.     TranslucencyTableHandle = (unsigned char **)Get1Resource('TTAB', resourceID);
  283.     if (TranslucencyTableHandle == NULL)
  284.     {
  285.         err = ResError();
  286.         if (err == noErr)
  287.             err = resNotFound;
  288.     }
  289.     
  290.     // If it's there then we copy it into our Array.
  291.     if (err == noErr) {    
  292.         HLock((Handle)TranslucencyTableHandle);
  293.         TranslucencyTableData = *TranslucencyTableHandle;
  294.         
  295.         // First store the number of translucency levels
  296.         gNumberOf8BitTranslucencyLevels = *TranslucencyTableData++;
  297.  
  298.         // then create a new translucency table
  299.         arraySize = gNumberOf8BitTranslucencyLevels * 65536 * sizeof(unsigned char);
  300.         g8BitTranslucencyTable = (unsigned char *)NewPtr(arraySize);
  301.         err = MemError();
  302.  
  303.         if (err == noErr) {
  304.         // and copy the data into the translucency table array
  305.             BlockMove(TranslucencyTableData,
  306.                       g8BitTranslucencyTable, 
  307.                       arraySize);
  308.         } else {
  309.             gNumberOf8BitTranslucencyLevels = 0;
  310.             g8BitTranslucencyTable = NULL;
  311.         }
  312.         HUnlock((Handle)TranslucencyTableHandle);
  313.     }
  314.  
  315.     
  316.     // Then we free up our loaded table, because we've copied it to our array.
  317.     if (TranslucencyTableHandle != NULL) {
  318.         ReleaseResource((Handle)TranslucencyTableHandle);
  319.     }
  320.         // SWStickyErr not set, because an error might be expected, and mean 
  321.         // the TTAB has to be calculated
  322.     return err;
  323. }
  324.  
  325.  
  326. ///--------------------------------------------------------------------------------------
  327. //    SWSave8BitTranslucencyTable
  328. ///--------------------------------------------------------------------------------------
  329. // This function will save the translucency table from a TTAB resource of the specified ID,
  330. // so it can be loaded later.  The format of the table is: the first byte is the number 
  331. // of levels of translucency, the subsequent bytes are the table.
  332.  
  333. OSErr SWSave8BitTranslucencyTable(short resourceID) {
  334.     Boolean        createdNewResource;
  335.     OSErr        err = noErr;
  336.     unsigned long arraySize;
  337.     unsigned char        **TranslucencyTableHandle;
  338.     unsigned char        *TranslucencyTableData;
  339.     
  340.     // Make sure there is a Translucency Table to save
  341.     if (g8BitTranslucencyTable == NULL) 
  342.         err = kNullTileMapErr;
  343.         
  344.     // Load or create the resource
  345.     if (err == noErr) {
  346.         arraySize = gNumberOf8BitTranslucencyLevels * 65536 * sizeof(unsigned char);
  347.  
  348.         // Check if the resource already exisits
  349.         TranslucencyTableHandle = (unsigned char **)Get1Resource('TTAB', resourceID);
  350.         
  351.         // If it already exists
  352.         if (TranslucencyTableHandle != NULL) {
  353.             SetHandleSize((Handle)TranslucencyTableHandle, arraySize + 1);
  354.             err = MemError();
  355.             // we free it up
  356.             if (err != noErr)
  357.                 ReleaseResource((Handle)TranslucencyTableHandle);
  358.             
  359.             createdNewResource = false;
  360.         }
  361.         // If it doesn't exist, we get some memory so we can create it
  362.         else if (ResError() == resNotFound || ResError() == noErr) {
  363.             TranslucencyTableHandle = (unsigned char **)NewHandle(arraySize + 1);
  364.             err = MemError();
  365.             createdNewResource = true;
  366.         }
  367.         else 
  368.             err = ResError();
  369.     }
  370.     // Copy the data into the resource handle
  371.     if (err == noErr) {    
  372.         HLock((Handle)TranslucencyTableHandle);
  373.         if (createdNewResource) {
  374.             AddResource((Handle)TranslucencyTableHandle, 'TTAB', resourceID, "\p");
  375.             err = ResError();
  376.             
  377.             HLock((Handle)TranslucencyTableHandle);
  378.             TranslucencyTableData = *TranslucencyTableHandle;
  379.             *TranslucencyTableData = (unsigned char)gNumberOf8BitTranslucencyLevels;
  380.             TranslucencyTableData++;
  381.             
  382.             // Copy the data from the translucency table array
  383.             BlockMove(g8BitTranslucencyTable,
  384.                       TranslucencyTableData, 
  385.                       arraySize);
  386.             
  387.             if (err != noErr)
  388.                 DisposeHandle((Handle)TranslucencyTableHandle);
  389.         
  390.         } else {
  391.             // If there is an error, free everthing up.
  392.             ChangedResource((Handle)TranslucencyTableHandle);
  393.             err = ResError();
  394.             
  395.             if (err != noErr)
  396.                 ReleaseResource((Handle)TranslucencyTableHandle);
  397.         }
  398.     }
  399.     // Update the resource file and clean up
  400.     if (err == noErr) {
  401.         UpdateResFile( CurResFile() );
  402.         ReleaseResource((Handle)TranslucencyTableHandle);
  403.     }
  404.     SWSetStickyIfError(err);
  405.     return err;
  406. }
  407.  
  408. // End Public Functions
  409. // ------------------------------------------------------------------------------
  410.  
  411.  
  412.  
  413.  
  414. // ------------------------------------------------------------------------------
  415. // ------------------------------------------------------------------------------
  416. // Our internal color table computation functions:
  417.  
  418. // -- ColorToIndex --
  419. // Given an RGB triplet, determine which color in the current CLUT
  420. // is closest and return the index of that color.
  421. unsigned char    ColorToIndex(long curRed, long curGreen, long curBlue) {
  422.     unsigned long j, dist, bestDist;
  423.     unsigned char bestMatch;
  424.     long rr, gg, bb;
  425.  
  426.     bestDist = 0xFFFFFFFF;
  427.     
  428.     for (j=0; j < kNumberOfColors; j++) {
  429.         rr = ABS(curRed - kSystemColorArray[j].red);
  430.         gg = ABS(curGreen - kSystemColorArray[j].green);
  431.         bb = ABS(curBlue - kSystemColorArray[j].blue);
  432.         dist = rr + gg + bb;
  433.         if (dist < bestDist) {
  434.             bestMatch = j;
  435.             bestDist = dist;
  436.         }
  437.     }
  438.     return bestMatch;
  439. }
  440.  
  441. // -- CalcNewColorValue --
  442. // Given two reds, greens or blues and a percent of translucency (from 0.0 to 1.0),
  443. // this calculates the blended version of the colors.  This is the actual work of
  444. // computing the translucent color.
  445. long     CalcNewColorValue (long sourceValue, long blendValue, float ratio) {
  446.     float newValue = (ratio * (float)sourceValue) + ((1.0 - ratio) * (float)blendValue);
  447.     return (long)newValue;
  448. }
  449.  
  450. // -- Calc8BitTranslucencyTable --
  451. // internal function that does the work.
  452. void     Calc8BitTranslucencyTable (int numberOfLevels) {
  453.     long curRed, curGreen, curBlue;
  454.     RGBColor curSourceColor, curBlendColor;
  455.     long sourceColor, blendColor;
  456.     long arrayIndex = 0;
  457.     unsigned char newIndex;
  458.     float curLevel, ratio;
  459.     // For each level of translucency
  460.     for (curLevel = 0.0; curLevel < numberOfLevels; curLevel += 1.0) {
  461.         // We calculate the current translucency percentage (between 0.0 and 1.0)
  462.         // (note we assume the user wants translucency levels evenly distributed
  463.         //  between (and not including) 0 and 1. 
  464.         ratio = ((curLevel + 1.0) / (numberOfLevels + 1.0));
  465.         // For each of our 256 possible source background colors
  466.         for (sourceColor = 0; sourceColor < kNumberOfColors; sourceColor++) {
  467.             curSourceColor = kSystemColorArray[sourceColor];
  468.             // For each of our 256 possible blended sprite colors 
  469.             for (blendColor = 0; blendColor < kNumberOfColors; blendColor++) {
  470.                 curBlendColor = kSystemColorArray[blendColor];
  471.                 // Calculate the value of the blended R, G, and B
  472.                 curRed = CalcNewColorValue(curSourceColor.red, curBlendColor.red, ratio);
  473.                 curGreen = CalcNewColorValue(curSourceColor.green, curBlendColor.green, ratio);
  474.                 curBlue = CalcNewColorValue(curSourceColor.blue, curBlendColor.blue, ratio);
  475.                 // And find the nearest color in our 256 color CLUT
  476.                 newIndex = ColorToIndex(curRed, curGreen, curBlue);
  477.                 // And store it in our table
  478.                 g8BitTranslucencyTable[arrayIndex] = newIndex;
  479.                 arrayIndex++;
  480.             }
  481.         }
  482.     }
  483. }
  484.  
  485.  
  486. // -- CreateCLUTTable --
  487. // This function loads the current CLUT into an array that we use 
  488. // when building our table.
  489. void CreateCLUTTable(void) {
  490.     GWorldPtr     theWorld;
  491.     GDHandle     theDevice;
  492.     short i;
  493.     PixMapHandle thePixMap;
  494.     GetGWorld(&theWorld, &theDevice);
  495.     thePixMap = GetGWorldPixMap(theWorld);
  496.     for (i=0;i<kNumberOfColors;i++) {
  497.         kSystemColorArray[i] = ((*((*thePixMap)->pmTable))->ctTable[i]).rgb;
  498.     }
  499. }
  500.  
  501.  
  502. #pragma mark -----8 Bit Drawing-----
  503. ///--------------------------------------------------------------------------------------
  504. ///--------------------------------------------------------------------------------------
  505. /// 8 Bit drawing
  506. ///--------------------------------------------------------------------------------------
  507. ///--------------------------------------------------------------------------------------
  508.  
  509.  
  510.  
  511. extern SInt8                 gSWmmuMode;
  512. extern SpritePtr            gCurrentSpriteBeingDrawn;
  513.  
  514. ///--------------------------------------------------------------------------------------
  515. //        BlitPixie8BitTranslucentMaskDrawProc
  516. ///--------------------------------------------------------------------------------------
  517. /// Same as BlitPixie8BitMaskDrawProc, only we take a translucent value
  518. /// and pass it to our translucent draw function.
  519. /// (How I miss decent macro facilities).
  520.  
  521. SW_FUNC void BlitPixie8BitTranslucentMaskDrawProc(
  522.     FramePtr srcFrameP,
  523.     FramePtr dstFrameP,
  524.     Rect *srcRect,
  525.     Rect *dstRect) 
  526. {
  527.     Rect dstBlitRect = *dstRect;
  528.     Rect srcBlitRect = *srcRect;
  529.     unsigned long         numBytesPerRow;
  530.     unsigned long         srcBaseOffset;
  531.     unsigned long         translucencyLevel = 0;
  532.     
  533.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  534.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 8);
  535.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 8);
  536.     SW_ASSERT(srcFrameP->maskPort != NULL);
  537.     SW_ASSERT(g8BitTranslucencyTable != NULL);
  538.  
  539.     if (gCurrentSpriteBeingDrawn != NULL)
  540.         translucencyLevel = gCurrentSpriteBeingDrawn->translucencyLevel;
  541.  
  542.     BP_CLIP_RECT(dstFrameP->frameRect, srcBlitRect, dstBlitRect);    
  543.     START_32_BIT_MODE
  544.     
  545.         // calculate the offset to the first byte of the source
  546.     srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - 
  547.         srcFrameP->frameRect.top] + srcBlitRect.left;
  548.  
  549.         // calculate the number of bytes in a row
  550.     numBytesPerRow = (dstBlitRect.right - dstBlitRect.left);
  551.  
  552.     BlitPixieTranslucentMask8Bit(
  553.             // calculate the address of the first byte of the source
  554.         (PixelPtr)(srcFrameP->frameBaseAddr + srcBaseOffset),
  555.  
  556.             // calculate the address of the first byte of the destination
  557.         (PixelPtr)(dstFrameP->frameBaseAddr + 
  558.             (dstFrameP->scanLinePtrArray[dstBlitRect.top]) + dstBlitRect.left),
  559.  
  560.             // calculate the address of the first byte of the mask
  561.         (PixelPtr)(srcFrameP->maskBaseAddr + srcBaseOffset),
  562.  
  563.             // calculate the number of rows to blit
  564.         dstBlitRect.bottom - dstBlitRect.top,
  565.  
  566.             // number of bytes in a row 
  567.         numBytesPerRow,
  568.  
  569.         // for PPC, just frameRowBytes
  570.     srcFrameP->frameRowBytes,
  571.     dstFrameP->frameRowBytes,
  572.         //Translucency Level
  573.     translucencyLevel
  574.     );
  575.  
  576.     END_32_BIT_MODE
  577. }
  578.  
  579. ///--------------------------------------------------------------------------------------
  580. //        TranslucencyConvertChar
  581. ///--------------------------------------------------------------------------------------
  582. // Blends a single pixel.
  583.  
  584. unsigned char SWInline TranslucencyConvertChar (
  585.     register unsigned char srcPixel, 
  586.     register unsigned char destPixel, 
  587.     register unsigned long maskPixel,
  588.     register unsigned char *tableAtLevel) {
  589.     
  590.     // If we are to draw it...
  591.     if (! (maskPixel))
  592.         // we need to generate an index of [source pixel][destination pixel] 
  593.         // into our lookup table.  The fastest way is to bitshift the source
  594.         // and OR it.  This generates a sixteen bit number, whose high eight bits
  595.         // are the source pixel and whose low eight bits are the destination pixel.
  596.         return tableAtLevel[((srcPixel << 8) | destPixel)];
  597.     else 
  598.         // otherwise, the mask says not to draw anything.
  599.         return destPixel;
  600. }
  601.  
  602. ///--------------------------------------------------------------------------------------
  603. //        TranslucencyConvertLong
  604. ///--------------------------------------------------------------------------------------
  605. // Blends four 8-bit pixels at a time.  Takes a source and destination long and generates
  606. // a new long representing the four pixels after blending.
  607.  
  608. #if USE_PPC_ASSEMBLY && __MWERKS__ >= 0x1800
  609. // If we are on PPC and CW Pro, we inline some assembly to minimize the number of instructions
  610. // per pixel.  The PPC can rotate, mask and splice the result all in one instruction.
  611. // This speeds this function up by about 10-15%
  612.  
  613. unsigned long SWInline TranslucencyConvertLong (
  614.     register unsigned long srcPixel, 
  615.     register unsigned long destPixel, 
  616.     register unsigned long maskPixel,
  617.     register unsigned char *tableAtLevel) {
  618.  
  619.     register unsigned long curSrc, colorValue;
  620.     // Do the first pixel (bits 24-31)
  621.     // We do this in an analogous way to the way we do a single pixel
  622.     // in TranslucencyConvertChar.  The only difference is that we have
  623.     // to mask off the pixels (using AND) and shift them around different 
  624.     // amounts so we can generate our 16 bit index.
  625.     // N.B. That each of these four operations compiles to a single PPC instruction.
  626.     if (! (maskPixel & 0xFF000000)) {                // is this pixel part of our sprite
  627.         curSrc = ((srcPixel >> 16) & 0x0000FF00);    // shift the source pixel over to be the high byte of our 16 bit index
  628.         __rlwimi(curSrc, destPixel, 8, 24, 31);        // shift the destination pixel over so it's the low byte of our 16 bit index
  629.                                                     // combine them into one index
  630.         colorValue = tableAtLevel[curSrc];            // look up the resulting pixel
  631.         __rlwimi(destPixel, colorValue, 24, 0, 7);    // and shift it back into place as our high end pixel
  632.     } 
  633.     
  634.     // Do the second pixel (bits 16-23) in a similar manner.
  635.     if (! (maskPixel & 0x00FF0000)) {
  636.         curSrc = ((srcPixel >> 8) & 0x0000FF00);
  637.         __rlwimi(    curSrc, destPixel, 16, 24, 31    );
  638.         colorValue = tableAtLevel[curSrc];
  639.         __rlwimi(    destPixel, colorValue, 16, 8, 15    );
  640.     }
  641.     
  642.     // Do the third pixel (bits 8-15) in a similar manner.
  643.     if (! (maskPixel & 0x0000FF00)) {
  644.         curSrc = (srcPixel & 0x0000FF00);
  645.         __rlwimi(    curSrc, destPixel, 24, 24, 31    );
  646.         colorValue = tableAtLevel[curSrc];
  647.         __rlwimi(    destPixel, colorValue, 8, 16, 23    );
  648.     } 
  649.     
  650.     // Do the fourth pixel (bits 0-7) in a similar manner.
  651.     if (! (maskPixel & 0x000000FF)) {
  652.         curSrc = (srcPixel & 0x000000FF) << 8;
  653.         __rlwimi(    curSrc, destPixel, 0, 24, 31    );
  654.         colorValue = tableAtLevel[curSrc];
  655.         __rlwimi(    destPixel, colorValue, 0, 24, 31    );
  656.     }
  657.     
  658.     // return the four pixels we've computed
  659.     return destPixel;    
  660. }
  661.  
  662. #else
  663.  
  664. unsigned long SWInline TranslucencyConvertLong (
  665.     register unsigned long srcPixel, 
  666.     register unsigned long destPixel, 
  667.     register unsigned long maskPixel,
  668.     register unsigned char *tableAtLevel) {
  669.     register unsigned long curSrc, curDest;
  670.     register unsigned long colorValue;
  671.     register unsigned long result = 0L;
  672.     register unsigned long index;
  673.     
  674.     // Do the first pixel (bits 24-31)
  675.     // We do this in an analogous way to the way we do a single pixel
  676.     // in TranslucencyConvertChar.  The only difference is that we have
  677.     // to mask off the pixels (using AND) and shift them around different 
  678.     // amounts so we can generate our 16 bit index.
  679.     if (! (maskPixel & 0xFF000000)) {                // is this pixel part of our sprite
  680.         curSrc = ((srcPixel >> 16) & 0x0000FF00);    // shift the source pixel over to be the high byte of our 16 bit index
  681.         curDest = destPixel >> 24;                    // shift the destination pixel over so it's the low byte of our 16 bit index
  682.         index = curSrc | curDest;                    // combine them into one index
  683.         colorValue = tableAtLevel[index];            // look up the resulting pixel
  684.         result = colorValue << 24;                    // and shift it back into place as our high end pixel
  685.     } else result = (destPixel & 0xFF000000);
  686.     
  687.     // Do the second pixel (bits 16-23) in a similar manner.
  688.     if (! (maskPixel & 0x00FF0000)) {
  689.         curSrc = ((srcPixel >> 8) & 0x0000FF00);
  690.         curDest = (destPixel >> 16) & 0x000000FF;
  691.         index = curSrc | curDest;
  692.         colorValue = tableAtLevel[index];
  693.         result = (colorValue << 16) | result;
  694.     } else result |= (destPixel & 0x00FF0000);
  695.     
  696.     // Do the third pixel (bits 8-15) in a similar manner.
  697.     if (! (maskPixel & 0x0000FF00)) {
  698.         curSrc = (srcPixel & 0x0000FF00);
  699.         curDest = (destPixel >> 8) & 0x000000FF;
  700.         index = curSrc | curDest;
  701.         colorValue = tableAtLevel[index];
  702.         result = (colorValue << 8) | result;
  703.     } else result |= (destPixel & 0x0000FF00);
  704.     
  705.     // Do the fourth pixel (bits 0-7) in a similar manner.
  706.     if (! (maskPixel & 0x000000FF)) {
  707.         curSrc = (srcPixel & 0x000000FF) << 8;
  708.         curDest = (destPixel & 0x000000FF);
  709.         index = curSrc | curDest;
  710.         colorValue = tableAtLevel[index];
  711.         result = colorValue | result;
  712.     } else result = (destPixel & 0x000000FF) | result;
  713.     
  714.     // return the four pixels we've computed
  715.     return result;    
  716. }
  717.  
  718. #endif
  719.  
  720. ///--------------------------------------------------------------------------------------
  721. //        BlitPixieTranslucentMask8Bit
  722. ///--------------------------------------------------------------------------------------
  723. // Modified version of SpriteWorld's standard 8-bit blitter.
  724. // Note that translucencyLevel is preshifted in this case << 16.
  725. // This is so we can OR it with the source and dest pixels in our conversion
  726.  
  727. SW_FUNC void BlitPixieTranslucentMask8Bit(
  728.     register PixelPtr srcPixelP,
  729.     register PixelPtr dstPixelP,
  730.     register PixelPtr maskPixelP,
  731.     register unsigned long rowsToCopy,
  732.     register unsigned long numBytesPerRow,
  733.     register unsigned long srcOffset,
  734.     register unsigned long dstOffset,
  735.     unsigned long translucencyLevel)
  736. {
  737.     register long index;
  738.     register PixelPtr startSrcPixelP;
  739.     register PixelPtr startDstPixelP;
  740.     register PixelPtr startMaskPixelP;
  741.  
  742.     // Since we know the level of translucency, we go to that levels 256x256 table.
  743.     // By doing this here, we only have to do it once.  Now a sixteen bit index
  744.     // we let us find the proper color (i.e. [sourceColorByte][destColorByte])
  745.     register unsigned char *tableAtLevel = &g8BitTranslucencyTable[translucencyLevel];
  746.     
  747.     startSrcPixelP = srcPixelP;
  748.     startDstPixelP = dstPixelP;
  749.     startMaskPixelP = maskPixelP;
  750.     
  751.     while (rowsToCopy--)    
  752.     {
  753.         register fourblits = (numBytesPerRow >> 2);
  754.         
  755.         srcPixelP = startSrcPixelP;
  756.         dstPixelP = startDstPixelP;
  757.         maskPixelP = startMaskPixelP;
  758.         
  759.         for (index = 0; index < fourblits; index++) {
  760.             register unsigned long temp1;
  761.             // For these four pixels, do the lookups to figure out the 
  762.             // pixels that need to be put on the screen.
  763.             temp1 =  TranslucencyConvertLong (srcPixelP[index], 
  764.                                                 dstPixelP[index], 
  765.                                                 maskPixelP[index],
  766.                                                 tableAtLevel);
  767.             // And blit it.
  768.             dstPixelP[index] = temp1;
  769.         }
  770.         srcPixelP += fourblits;
  771.         dstPixelP += fourblits;
  772.         maskPixelP += fourblits;
  773.         
  774.         // If we have any leftover pixels, do them.
  775.         // note we could speed this case up by making a TranslucencyConvertWord
  776.         if (numBytesPerRow & 0x2) {
  777.             register unsigned char temp1;
  778.  
  779.             #ifdef __MWERKS__  // Do it nicely
  780.                 temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP)++, 
  781.                                                 *((unsigned char *) dstPixelP), 
  782.                                                 *((unsigned char *) maskPixelP)++,
  783.                                                 tableAtLevel);
  784.                 (*((unsigned char *) dstPixelP)++) = temp1;
  785.                 temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP)++, 
  786.                                                 *((unsigned char *) dstPixelP), 
  787.                                                 *((unsigned char *) maskPixelP)++,
  788.                                                 tableAtLevel);
  789.                 (*((unsigned char *) dstPixelP)++) = temp1;
  790.             #else                 //Do the simplified (and slower) ThinkC way
  791.  
  792.                 temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP), 
  793.                                                 *((unsigned char *) dstPixelP), 
  794.                                                 *((unsigned char *) maskPixelP),
  795.                                                 tableAtLevel);
  796.                 (*((unsigned char *) dstPixelP)) = temp1;
  797.                 
  798.                     // this painfully convoluted syntax is required to make ThinkC 6/7 happy
  799.                 srcPixelP = (PixelPtr)(((char*)srcPixelP) + 1);
  800.                 dstPixelP = (PixelPtr)(((char*)dstPixelP) + 1);
  801.                 maskPixelP = (PixelPtr)(((char*)maskPixelP) + 1);
  802.                 
  803.                 temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP), 
  804.                                                 *((unsigned char *) dstPixelP), 
  805.                                                 *((unsigned char *) maskPixelP),
  806.                                                 tableAtLevel);
  807.                 (*((unsigned char *) dstPixelP)) = temp1;
  808.                 
  809.                 srcPixelP = (PixelPtr)(((char*)srcPixelP) + 1);
  810.                 dstPixelP = (PixelPtr)(((char*)dstPixelP) + 1);
  811.                 maskPixelP = (PixelPtr)(((char*)maskPixelP) + 1);
  812.             #endif
  813.         }
  814.         if (numBytesPerRow & 0x1) {            
  815.             register unsigned char temp1;
  816.             #ifdef __MWERKS__  // Do it nicely
  817.                 temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP)++, 
  818.                                                 *((unsigned char *) dstPixelP), 
  819.                                                 *((unsigned char *) maskPixelP)++,
  820.                                                 tableAtLevel);
  821.                 (*((unsigned char *) dstPixelP)++) = temp1;
  822.  
  823.             #else                 //Do the simplified (and slower) ThinkC way
  824.                 temp1 = TranslucencyConvertChar (*((unsigned char *) srcPixelP), 
  825.                                                 *((unsigned char *) dstPixelP), 
  826.                                                 *((unsigned char *) maskPixelP),
  827.                                                 tableAtLevel);
  828.                 (*((unsigned char *) dstPixelP)) = temp1;
  829.                 
  830.                 srcPixelP = (PixelPtr)(((char*)srcPixelP) + 1);
  831.                 dstPixelP = (PixelPtr)(((char*)dstPixelP) + 1);
  832.                 maskPixelP = (PixelPtr)(((char*)maskPixelP) + 1);
  833.             #endif
  834.         }
  835.  
  836.             // bump to next row
  837.         startSrcPixelP = (PixelPtr)(((char*)startSrcPixelP) + srcOffset);
  838.         startDstPixelP = (PixelPtr)(((char*)startDstPixelP) + dstOffset);
  839.         startMaskPixelP = (PixelPtr)(((char*)startMaskPixelP) + srcOffset);
  840.     }
  841. }
  842.  
  843. // A useful helper function
  844. unsigned long Blend8BitPixels (int level, int source, int dest) {
  845.     return g8BitTranslucencyTable[((level << 16) | (source << 8) | dest)];
  846. }
  847.  
  848. ///--------------------------------------------------------------------------------------
  849. ///--------------------------------------------------------------------------------------
  850. ///16 Bit Translucency Blitters
  851. ///--------------------------------------------------------------------------------------
  852. ///--------------------------------------------------------------------------------------
  853.  
  854. #pragma mark -----16 Bit Table Management-----
  855. ///--------------------------------------------------------------------------------------
  856. ///--------------------------------------------------------------------------------------
  857.  
  858. Ptr             gStorageP = NULL;                
  859. unsigned char     *g16BitTranslucencyTable = NULL;
  860.  
  861. OSErr SWCreate16BitTranslucencyTable( void )
  862. {
  863.     register float             alpha,beta,source_multiplied,source_intensity,destination_intensity;
  864.     register long             i;
  865.     register unsigned char     *table_ptr;
  866.     OSErr                    err = noErr;
  867.  
  868.     if (g16BitTranslucencyTable != NULL)
  869.         err = kAlreadyCalledErr;
  870.     
  871.     if (err == noErr)
  872.     {
  873.             // Put the table on a 64k boundary
  874.         gStorageP = NewPtr(32768 + 65536); // 15 bits + 64K Boundary
  875.         if (gStorageP == NULL)
  876.             err = MemError();
  877.     }
  878.     
  879.     
  880.     if (err == noErr)
  881.     {    
  882.         g16BitTranslucencyTable = table_ptr = (unsigned char*)(((long)gStorageP | 0xffff)+1);
  883.         
  884.         /* table lookup offset format: 15 bits
  885.  
  886.              a= alpha
  887.              s= source channel
  888.              d= dest channel
  889.  
  890.             [a][s][d]
  891.             
  892.              offset = aaaaasssssddddd
  893.  
  894.             
  895.              Side note:
  896.              offset=aaaaaXsssssddddd may be kinder on the cache.
  897.         */
  898.         
  899.         for (i=0;i<kNumberOf16BitTranslucencyLevels;i++)
  900.         {
  901.             alpha = ((float)i)/((float)kNumberOf16BitTranslucencyLevels - 1.0);
  902.             beta = 1.0 - alpha;
  903.             for (source_intensity=0;source_intensity<kNumberOf16BitTranslucencyLevels;source_intensity+=1.0)
  904.             {
  905.                 source_multiplied = source_intensity * alpha;
  906.                 
  907.                 for (destination_intensity=0; destination_intensity<kNumberOf16BitTranslucencyLevels; destination_intensity+=1.0)    
  908.                     *table_ptr++ = source_multiplied + (destination_intensity * beta);
  909.             }
  910.         }
  911.     }
  912.     
  913.     return err;
  914. }
  915.  
  916. ///--------------------------------------------------------------------------------------
  917. //  -- SWDispose16BitTranslucencyTable --
  918. ///--------------------------------------------------------------------------------------
  919. // This function must be called to clear the table from memory.
  920.  
  921. void     SWDispose16BitTranslucencyTable(void)
  922. {
  923.         // Only do this if we've created a table.
  924.     if (gStorageP != NULL)
  925.     {
  926.         DisposePtr((Ptr)gStorageP);
  927.         gStorageP = NULL;
  928.         g16BitTranslucencyTable = NULL;
  929.     }
  930. }
  931.  
  932.  
  933. #pragma mark -----16 Bit Blitters-----
  934. ///--------------------------------------------------------------------------------------
  935. //        BlitPixie16BitTranslucentMaskDrawProc
  936. ///--------------------------------------------------------------------------------------
  937.  
  938. SW_FUNC void BlitPixie16BitTranslucentMaskDrawProc (
  939.     FramePtr srcFrameP,
  940.     FramePtr dstFrameP,
  941.     Rect *srcRect,
  942.     Rect *dstRect)
  943. {
  944.     Rect dstBlitRect = *dstRect;
  945.     Rect srcBlitRect = *srcRect;
  946.     unsigned long         srcBaseOffset;
  947.     unsigned long         translucencyLevel = 0;
  948.     unsigned long         height;
  949.     unsigned long         width;
  950.     unsigned long         packedHeightAndWidth;
  951.  
  952.     SW_ASSERT(srcFrameP->isFrameLocked && dstFrameP->isFrameLocked);
  953.     SW_ASSERT((*srcFrameP->framePort->portPixMap)->pixelSize == 16);
  954.     SW_ASSERT((*dstFrameP->framePort->portPixMap)->pixelSize == 16);
  955.     SW_ASSERT(srcFrameP->maskPort != NULL);
  956.     SW_ASSERT(g16BitTranslucencyTable != NULL);
  957.     
  958.     if (gCurrentSpriteBeingDrawn != NULL)
  959.         translucencyLevel = gCurrentSpriteBeingDrawn->translucencyLevel;
  960.  
  961.     BP_CLIP_RECT(dstFrameP->frameRect, srcBlitRect, dstBlitRect);    
  962.     START_32_BIT_MODE
  963.     
  964.         // Must be calculated *after* clipping the Sprite!
  965.     height = dstBlitRect.bottom - dstBlitRect.top;
  966.     width  = dstBlitRect.right  - dstBlitRect.left;
  967.     packedHeightAndWidth = ((height & 0x0000FFFF) << 16) | (width & 0x0000FFFF);
  968.  
  969.         // calculate the offset to the first byte of the source
  970.     srcBaseOffset = srcFrameP->scanLinePtrArray[srcBlitRect.top - 
  971.         srcFrameP->frameRect.top] + 
  972.         (srcBlitRect.left << 1);
  973.  
  974.         // calculate the number of bytes in a row
  975.  
  976.     BlitPixieTranslucencyMask16Bit(
  977.         g16BitTranslucencyTable,
  978.  
  979.             // calculate the address of the first byte of the source
  980.         (short *)(srcFrameP->frameBaseAddr + srcBaseOffset),
  981.  
  982.             // calculate the address of the first byte of the destination
  983.         (short *)(dstFrameP->frameBaseAddr + 
  984.             (dstFrameP->scanLinePtrArray[dstBlitRect.top]) + 
  985.             (dstBlitRect.left << 1)),
  986.  
  987.             // calculate the address of the first byte of the mask
  988.         (short *)(srcFrameP->maskBaseAddr + 
  989.                 srcBaseOffset),
  990.  
  991.             // the number of rows to blit and number of row bytes, packed together
  992.         packedHeightAndWidth,
  993.  
  994.             // for PPC, just frameRowBytes
  995.         srcFrameP->frameRowBytes,
  996.         dstFrameP->frameRowBytes,
  997.         
  998.         translucencyLevel);
  999.  
  1000.     END_32_BIT_MODE
  1001. }
  1002.  
  1003.  
  1004. ///--------------------------------------------------------------------------------------
  1005. ///--------------------------------------------------------------------------------------
  1006.  
  1007.  
  1008. #if USE_PPC_ASSEMBLY
  1009.  
  1010. /*
  1011.     16-Bit Masked Translucency Blitter
  1012.  
  1013.     Adapted from Alex Clarke's alphaBlend rect blitter.
  1014.     - Added masking
  1015.     - Adjusted it to deal with sprite world style sources
  1016.     - Packed Height and width so we only have 8 args
  1017.     - Wrote C version so it compiles on 68K.
  1018.  
  1019. */
  1020.  
  1021. // Some defines to make this easier to read
  1022. #define lookup_offset1 alpha
  1023. #define lookup_offset2 r11
  1024. #define lookup_offset3 r12
  1025. #define height r13
  1026. #define width r14
  1027. #define tmp1 r0
  1028. #define tmp2 r31
  1029. #define tmp3 r30
  1030. #define mask_checker tmp3
  1031.  
  1032. void asm BlitPixieTranslucencyMask16Bit (    
  1033.                 register unsigned char *lookup_ptr,
  1034.                 register short *srcPtr,
  1035.                 register short *dstPtr,
  1036.                 register short *maskPtr,
  1037.                 register unsigned long heightAndWidth,
  1038.                 register long srcRowBytes,
  1039.                 register long dstRowBytes,
  1040.                 register long alpha
  1041.                 ) {
  1042.  
  1043.     //store all our temp variables on the stack 
  1044.     stw     tmp2,-4(SP)    
  1045.     stw     tmp3,-8(SP)
  1046.     stw     height,-12(SP)
  1047.     stw     width,-16(SP)
  1048.     stw     lookup_offset2,-20(SP)
  1049.     stw     lookup_offset3,-24(SP)
  1050.  
  1051.     // Pull out the height and width
  1052.     // we pack these two into one because MWerks only allows us to have 8 
  1053.     // function arguments declared as "register".
  1054.     rlwinm   height, heightAndWidth,16, 16, 31
  1055.     rlwinm   width,  heightAndWidth, 0, 16, 31
  1056.  
  1057.     // We need to make the rowBytes be rowBytes - width because we are using
  1058.     // preincrements when getting and setting the pixels
  1059.     add        tmp1, width, width                //adjust for pixels being 2 bytes long
  1060.     sub        srcRowBytes,srcRowBytes,tmp1    //calculateoffsets to the next row
  1061.     sub        dstRowBytes,dstRowBytes,tmp1
  1062.  
  1063.     subi    srcPtr,srcPtr,2    //adjust the pointers so we can use pre-increments
  1064.     subi    maskPtr,maskPtr,2    //adjust the pointers so we can use pre-increments
  1065.     subi    dstPtr,dstPtr,2
  1066.     
  1067.     // Set up the offsets into the blending table for each of our R, G, and B lookups
  1068.     // by setting the high order five bits to the alpha color
  1069.     // Note that these high order bits never get changed as we
  1070.     // work on our pixels, so the alpha (translucency level)
  1071.     // stays the same
  1072.     rlwinm    lookup_offset3,alpha,10,17,21 
  1073.     mr        lookup_offset2,lookup_offset3
  1074.     mr        lookup_offset1,lookup_offset3
  1075.     
  1076. @yloop
  1077.     mtctr     width                                    //set the ctr to so we copy do WIDTH number of pixels
  1078.  
  1079.         @xloop
  1080.             lhzu    tmp1,2(srcPtr)                    //load the source and destination colour
  1081.             lhz     tmp2,2(dstPtr)
  1082.             
  1083.             lhzu     mask_checker, 2(maskPtr)        // load the mask
  1084.             cmpwi    mask_checker, 0                    // if it is not zero
  1085.             bne        @skipBlittingThisPixel            // then keep going
  1086.  
  1087.             rlwimi    lookup_offset3,tmp1,5,22,26        //blue channel source
  1088.             rlwimi    lookup_offset2,tmp1,0,22,26        //green channel source
  1089.             rlwimi    lookup_offset1,tmp1,27,22,26    //red channel source    
  1090.             
  1091.             rlwimi    lookup_offset3,tmp2,0,27,31        //blue channel destination    
  1092.             rlwimi    lookup_offset2,tmp2,27,27,31    //green channel destination
  1093.             rlwimi    lookup_offset1,tmp2,22,27,31    //red channel destination
  1094.             
  1095.             lbzx    tmp3,lookup_ptr,lookup_offset3    //load blended blue channel
  1096.             lbzx    tmp2,lookup_ptr,lookup_offset2    //load blended green channel
  1097.             lbzx    tmp1,lookup_ptr,lookup_offset1    //load blended red channel
  1098.             
  1099.             rlwimi    tmp3,tmp2,5,22,26                //insert green channel into result
  1100.             rlwimi    tmp3,tmp1,10,17,21                //insert red channel into result
  1101.             
  1102.             sthu    tmp3,2(dstPtr)                    //store result
  1103.  
  1104.         @endOfBlitXLoop
  1105.             bdnz    @xloop                            // decrement the ctr and see if we're done                
  1106.     
  1107.     // Now we move the pointers forward to the next row
  1108.     add        srcPtr,srcPtr,srcRowBytes
  1109.     add        dstPtr,dstPtr,dstRowBytes    
  1110.     add        maskPtr,maskPtr,srcRowBytes    
  1111.     
  1112.     //and if we haven't finished, continue
  1113.     subi    height,height,1            
  1114.     cmpwi    height,0
  1115.     bne        @yloop    
  1116.     
  1117.     lwz     tmp2,-4(SP)            //clean up, restore registers we've been using
  1118.     lwz     tmp3,-8(SP)
  1119.     lwz     height,-12(SP)
  1120.     lwz     width,-16(SP)
  1121.     lwz     lookup_offset2,-20(SP)
  1122.     lwz     lookup_offset3,-24(SP)
  1123.  
  1124.  
  1125.     blr
  1126.  
  1127. // Little subroutine to make sure to increment the dstPtr when
  1128. // the mask tells us not to blit 
  1129. @skipBlittingThisPixel
  1130.     addi     dstPtr, dstPtr, 2
  1131.     b         @endOfBlitXLoop
  1132. }
  1133.  
  1134.  
  1135.  
  1136. #undef lookup_offset1
  1137. #undef lookup_offset2
  1138. #undef lookup_offset3
  1139. #undef tmp1
  1140. #undef tmp2
  1141. #undef tmp3
  1142. #undef mask_checker
  1143. #undef width
  1144. #undef height
  1145.  
  1146.  
  1147. #else /* USE_PPC_ASSEMBLY */
  1148.  
  1149. // here is a C version of the above function.  
  1150.  
  1151. void BlitPixieTranslucencyMask16Bit (    
  1152.                 register unsigned char *lookup_ptr,
  1153.                 register short *srcPtr,
  1154.                 register short *dstPtr,
  1155.                 register short *maskPtr,
  1156.                 register unsigned long heightAndWidth,
  1157.                 register long srcRowBytes,
  1158.                 register long dstRowBytes,
  1159.                 register long alpha
  1160.                 ) {
  1161.      register unsigned long height = heightAndWidth >> 16;
  1162.      register unsigned long width = heightAndWidth & 0x0000FFFF;
  1163.      register unsigned long lookup_offset_blue, lookup_offset_green, lookup_offset_red, counter;
  1164.      register unsigned long final_red, final_green, final_result;
  1165.     register short curSource, curDest, curMask;
  1166.  
  1167.     srcRowBytes -= width * 2;
  1168.     dstRowBytes -= width * 2;
  1169.  
  1170.     while (height > 0) {
  1171.         counter = width;
  1172.         while (counter > 0) {
  1173.             lookup_offset_blue = lookup_offset_green = lookup_offset_red = alpha << 10;
  1174.             curSource = *srcPtr++;
  1175.             curMask = *maskPtr++;
  1176.             curDest = *dstPtr;
  1177.             if (curMask == 0) {
  1178.                 lookup_offset_blue |= (curSource << 5) & 0x03E0;
  1179.                 lookup_offset_green |= curSource & 0x03E0;
  1180.                 lookup_offset_red |= (curSource >> 5) & 0x03E0;
  1181.  
  1182.                 lookup_offset_blue |= curDest & 0x001F;
  1183.                 lookup_offset_green |= (curDest >> 5) & 0x001F;
  1184.                 lookup_offset_red |= (curDest >> 10) & 0x001F;
  1185.  
  1186.                 final_red = lookup_ptr[lookup_offset_red];
  1187.                 final_green = lookup_ptr[lookup_offset_green];
  1188.                 final_result = lookup_ptr[lookup_offset_blue];
  1189.  
  1190.                 final_result |= final_green << 5;
  1191.                 final_result |= final_red << 10;
  1192.  
  1193.                 *dstPtr++ = final_result;
  1194.             } else {
  1195.                 dstPtr++;
  1196.             }
  1197.             counter--;
  1198.         }
  1199.  
  1200.         #ifdef MWERKS
  1201.         (char *)srcPtr += srcRowBytes;
  1202.         (char *)maskPtr += srcRowBytes;
  1203.         (char *)dstPtr += dstRowBytes;
  1204.         #else
  1205.         srcPtr = (short *)(((char*)srcPtr) + srcRowBytes);
  1206.         dstPtr = (short *)(((char*)dstPtr) + dstRowBytes);
  1207.         maskPtr = (short *)(((char*)maskPtr) + srcRowBytes);
  1208.         #endif
  1209.  
  1210.         height--;
  1211.     }    
  1212.  
  1213. }
  1214. #endif /* USE_PPC_ASSEMBLY */
  1215.  
  1216.  
  1217. // A useful helper function
  1218. unsigned long Blend16BitPixels (int level, int source, int dest) {
  1219.      register unsigned long lookup_offset_blue, lookup_offset_green, lookup_offset_red;
  1220.      register unsigned long final_red, final_green, final_result;
  1221.  
  1222.     lookup_offset_blue = lookup_offset_green = lookup_offset_red = level << 10;
  1223.     
  1224.     lookup_offset_blue |= (source << 5) & 0x03E0;
  1225.     lookup_offset_green |= source & 0x03E0;
  1226.     lookup_offset_red |= (source >> 5) & 0x03E0;
  1227.  
  1228.     lookup_offset_blue |= dest & 0x001F;
  1229.     lookup_offset_green |= (dest >> 5) & 0x001F;
  1230.     lookup_offset_red |= (dest >> 10) & 0x001F;
  1231.  
  1232.     final_red = g16BitTranslucencyTable[lookup_offset_red];
  1233.     final_green = g16BitTranslucencyTable[lookup_offset_green];
  1234.     final_result = g16BitTranslucencyTable[lookup_offset_blue];
  1235.  
  1236.     final_result |= final_green << 5;
  1237.     final_result |= final_red << 10;
  1238.  
  1239.     return final_result;
  1240. }
  1241.  
  1242.